home *** CD-ROM | disk | FTP | other *** search
- /*
- ** Apple Macintosh Developer Technical Support
- **
- ** File: Window.c
- ** Written by: Eric Soldan
- **
- ** Copyright © 1990-1993 Apple Computer, Inc.
- ** All rights reserved.
- */
-
- /* You may incorporate this sample code into your applications without
- ** restriction, though the sample code has been provided "AS IS" and the
- ** responsibility for its operation is 100% yours. However, what you are
- ** not permitted to do is to redistribute the source as "DSC Sample Code"
- ** after having made changes. If you're going to re-distribute the source,
- ** we require that you make it clear in the source that the code was
- ** descended from Apple Sample Code, but that you've made changes. */
-
- /* This file contains the code for the document procedure pointers for the main Wannabe
- ** document. Wannabe currently only supports one type of documents, type 'DUMD',
- ** which stands for "DUMb Document". */
-
- /* For more information on this file, please read the read.me file "=How to write your app". */
-
-
-
- /*****************************************************************************/
-
-
-
- #include "App.h" /* Get the application includes/typedefs, etc. */
- #include "App.defs.h" /* Get various application definitions. */
- #include "App.protos.h" /* Get the prototypes for application. */
-
- #ifndef __ERRORS__
- #include <Errors.h>
- #endif
-
- #ifndef __FONTS__
- #include <Fonts.h>
- #endif
-
- #ifndef __RESOURCES__
- #include <Resources.h>
- #endif
-
- #ifndef __TOOLUTILS__
- #include <ToolUtils.h>
- #endif
-
- #ifndef __UTILITIES__
- #include "Utilities.h"
- #endif
-
-
-
- /*****************************************************************************/
-
-
-
- Boolean gNoDefaultDocument = false;
- /* Set to true if app should boot with no default document. */
- /* This tells DTS.Lib..framework what you want. */
-
- OSType gAppWindowType = kDocFileType; /* Main document type. */
- long gAppWindowAttr = kwAppWindow; /* Main window attributes. */
-
- short gMinVersion = kMinVersion; /* Minimum document version app can support. */
- short gMaxVersion = kMaxVersion; /* Maximum document version app can support. */
- /* More informing DTS.Lib..framework. */
-
- extern Boolean gStartingUp;
-
- extern short gPrintPage; /* Non-zero means we are printing. */
- /* DTS.Lib..framework global. */
-
- extern RgnHandle gCursorRgn; /* We handle cursors here, so we need */
- extern CursPtr gCursorPtr; /* to know about these things. */
- /* Above are DTS.Lib..framework globals. */
-
- /* Currently Wannabe doesn't ever change the cursor, so we don't actually need
- ** these referenced here. However, since Wannabe is supposed to be an application in
- ** progress, it is very likely that you will need to reference these as your project
- ** develops. See DTS.StyleChat and DTS.Draw for examples of setting the cursor. */
-
- /* Some cursors are pointer-based, and some cursors are resource-based.
- ** If a cursor is resource-based, it needs to be loaded and made to not move,
- ** and then gCursorPtr can be set to point to it. This makes all cursors
- ** pointer-based. Also, gCursorPtr is used by DTS.Lib..framework to
- ** determine if there is a current cursor. If gCursorPtr is nil, then
- ** there is no current cursor, and the cursor has to be recalculated, no
- ** matter where the mouse is. If gCursorPtr is not nil, then if the
- ** mouse position is within the cursor region gCursorRgn, the cursor is
- ** correct, and no recalculation is necessary. If it is outside this region,
- ** then it is recalculated. What does this all mean? It means that if you
- ** want to guarantee that the cursor is recalculated next time DoWindowCursor()
- ** is called, set gCursorPtr to nil.
- **
- ** If you have a cursor resource, you need to:
- ** 1) Load the resource.
- ** 2) Make a fixed copy of it.
- ** 3) Set the cursor to it.
- ** 4) Set gCursorPtr to point to the fixed copy.
- **
- ** There is a function that does almost all of this, called DoSetResCursor().
- ** It does all but set gCursorPtr to it. (It actually sets gCursorPtr to nil.)
- ** It does return a pointer to the permanent copy, so typically what you will
- ** want to do is the following:
- ** gCursorPtr = DoSetResCursor(theCursorID);
- **
- ** So why set gCursorPtr to nil as the default action? This allows you to
- ** set a temporary cursor, which will be replaced when DoWindowCursor() is
- ** called next, or it allows you to set a cursor that maps to the cursor
- ** region gCursorRgn (by setting gCursorPtr to the return result). */
-
- static Boolean GoFast(TEHandle teHndl, EventRecord *event);
-
-
-
- /*****************************************************************************/
- /*****************************************************************************/
-
-
-
- /* •• You don't call this. DTS.Lib..framework does for appropriate document type(s). •• */
-
- /* Calculate application specific frame area (Called by DoCalcFrameRgn).
- ** You are passed an empty region. You are supposed to add any custom frame
- ** parts that this document uses. Typically there are no frame portions, as
- ** they are accounted for in other ways. The scrollbars and grow icon will
- ** automatically be contributed to the calculation of the frame region.
- ** If you use sidebars, these are also added in automatically. This is only
- ** used if the frame region is more complicated than can automatically be
- ** handled. So, almost always, you will simply leave the region empty. */
-
- #pragma segment TheDoc
- void CalcFrameRgn(FileRecHndl frHndl, WindowPtr window, RgnHandle rgn)
- {
- #ifndef __MWERKS__
- #pragma unused (frHndl, window, rgn)
- #endif
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* •• You don't call this. DTS.Lib..framework does for appropriate document type(s). •• */
-
- /* This is called (by DoContentClick()) when a mouse-down event occurs in the content of
- ** a window. Other applications might want to call FindControl, TEClick, etc., to
- ** further process the click. */
-
- #pragma segment TheDoc
- void ContentClick(WindowPtr window, EventRecord *event, Boolean firstClick)
- {
- #ifndef __MWERKS__
- #pragma unused (firstClick)
- #endif
-
- ControlHandle ctl;
- short action, cnum;
- FileRecHndl frHndl;
-
- cnum = IsCtlEvent(window, event, &ctl, &action);
- /* That was easy. Scrolling was just handled. Other stuff would be handled
- ** by IsCtlEvent, if we had other stuff to do. We don't have any other
- ** controls in the content besides the document scrollbars. */
-
- frHndl = (FileRecHndl)GetWRefCon(window);
- switch (cnum) {
- case 1000:
- SendMessage(frHndl, kStylMssg);
- SendMessage(frHndl, kTextMssg);
- break;
- case 1010:
- AllowAutoReconnect(frHndl);
- SendConnect(frHndl, (char *)"\pDTS.Chat");
- SetWindowDirty(window);
- break;
- case 1020:
- if ((*frHndl)->connect.connected) {
- SendMessage(frHndl, kDisconnectMssg);
- (*frHndl)->connect.remotePath[0] = 0;
- }
- CNum2Ctl(window, 1020, &ctl);
- (*ctl)->contrlVis = false;
- BeginFrame(window);
- CNum2Ctl(window, 1010, &ctl);
- ShowStyledControl(ctl);
- CNum2Ctl(window, 1000, &ctl);
- (*ctl)->contrlVis = false;
- CNum2Ctl(window, 1002, &ctl);
- DoDraw1Control(ctl, false);
- EndFrame(window);
- break;
- }
-
- return;
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* •• You don't call this. DTS.Lib..framework does for appropriate document type(s). •• */
-
- /* DoKeyDown() is first called by the application. Then if the key isn't a menu
- ** key, DoKeyDown() calls this code. Here are the rules for this function:
- **
- ** 1) If you handle the key, return(true). This completes the key handling.
- ** 2) If you don't handle the key, you return false. However, there are two
- ** situations for not handling the key:
- ** a) You want someone else to.
- ** b) You want nobody else to look at the key.
- ** This is what the boolean passThrough is for. If you wish the next window
- ** to have a look at the key, set the boolean passThrough to true. passThrough
- ** is already initialized to false, which is the common case, so you only have
- ** to worry about setting it true.
- **
- ** If you have a window that never processes keys and always passes them through,
- ** just set the contentKeyProc to nil. This will indicate to the application
- ** framework that all keys should be passed through this window. DTS.Draw has
- ** such a window. Its palette window doesn't accept keys. They are passed through
- ** to document windows. */
-
- #pragma segment TheDoc
- Boolean ContentKey(WindowPtr window, EventRecord *event, Boolean *passThrough)
- {
- #ifndef __MWERKS__
- #pragma unused (passThrough)
- #endif
-
- short cnum, action;
- FileRecHndl frHndl;
-
- cnum = IsCtlEvent(window, event, nil, &action);
-
- frHndl = (FileRecHndl)GetWRefCon(window);
- switch (cnum) {
- case 101:
- if (action == 2) {
- SetWindowDirty(window);
- DoAdjustMenus();
- return(true);
- }
- break;
- case 1000:
- SendMessage(frHndl, kStylMssg);
- SendMessage(frHndl, kTextMssg);
- return(true);
- break;
- }
-
- return(false);
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* •• You don't call this. DTS.Lib..framework does for appropriate document type(s). •• */
-
- /* Draw application specific content (Called by DoDrawFrame).
- **
- ** If your application has any custom frame areas, or if it uses sidebars,
- ** this is the function that you would put the frame drawing code. The
- ** document scrollbars and grow icon drawing is handled by DTS.framework.
- ** Just do the sidebar and custom areas here. */
-
- #pragma segment TheDoc
- void DrawFrame(FileRecHndl frHndl, WindowPtr window, Boolean activate)
- {
- MoveTo(0, (*frHndl)->fileState.topSidebar - 1);
- LineTo((*frHndl)->fileState.leftSidebar - 1 - 16384, (*frHndl)->fileState.topSidebar - 1);
- LineTo((*frHndl)->fileState.leftSidebar - 1 - 16384, 16383);
-
- BeginFrame(window);
- DoDrawControls(window, activate);
- EndFrame(window);
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* •• You don't call this. DTS.Lib..framework does for appropriate document type(s). •• */
-
- /* Frees up any application-specific memory in the document. This is called by
- ** DoFreeDocument, which is called by DisposeDocument(). The application would
- ** call DisposeDocument(), not DoFreeDocument() or FreeDocument() directly.
- **
- ** The document may have a bunch of handles off the main handle of the document.
- ** This is where they are freed. DisposeDocument calls this prior to releasing
- ** the ram for the main handle of the document, so release everything else
- ** here, or you will have a memory leak.
- **
- ** NOTE: Calling DefaultFreeDocument() frees up all memory used by a
- ** hierarchical document (see TreeObj package). */
-
- #pragma segment TheDoc
- OSErr FreeDocument(FileRecHndl frHndl)
- {
- Handle textHndl;
- StScrpHandle textStyl;
-
- textHndl = (*frHndl)->d.doc.textHndl;
- if (textHndl) {
- DisposeHandle(textHndl);
- (*frHndl)->d.doc.textHndl = nil;
- }
- textStyl = (*frHndl)->d.doc.textStyl;
- if (textStyl) {
- DisposeHandle((Handle)textStyl);
- (*frHndl)->d.doc.textStyl = nil;
- }
- DefaultFreeDocument(frHndl);
-
- return(noErr);
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* •• You don't call this. DTS.Lib..framework does for appropriate document type(s). •• */
-
- /* Any additional window disposal tasks can be handled here. */
-
- #pragma segment TheDoc
- OSErr FreeWindow(FileRecHndl frHndl, WindowPtr window)
- {
- #ifndef __MWERKS__
- #pragma unused (window)
- #endif
-
- WindowPtr ww;
- FileRecHndl ff;
-
- SendMessage(frHndl, kDisconnectMssg);
- /* Let the remote user know the window is closing. We must handle this,
- ** as DTS.Lib..framework doesn't. it is application-specific. */
-
- if ((*frHndl)->fileState.sfType == kDocFileType) {
- for (ww = nil; (ww = GetNextWindow(ww, 0)) != nil;) {
- ff = (FileRecHndl)GetWRefCon(ww);
- if ((*ff)->fileState.sfType == kViewHierFileType) {
- if ((*frHndl)->d.doc.root == (*ff)->d.doc.root) {
- DisposeOneWindow(ww, kClose);
- ww = nil;
- }
- }
- }
- }
-
- return(noErr);
- /* We always return noErr here, even if SendMessage returned an error. Why?
- ** Because we don't want the closing of the window to halt just because the
- ** network connection may have been lost, which is about the only error that
- ** can occur. If there's something bogus about the window, we most likely
- ** want to get rid of it, with good riddance. */
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* •• You don't call this. DTS.Lib..framework does for appropriate document type(s). •• */
-
- /* Image the document into the current port.
- **
- ** The only thing tricky about this function is that it needs to key off of
- ** the global variable gPrintPage. gPrintPage is the current page that is
- ** being printed. If gPrintPage is 0, then you are drawing to the window.
- **
- ** For when printing:
- **
- ** If gPrintPage is non-0, that is the page to be printed. If after imaging
- ** the page there are no more pages, you should set gPrintPage to 0. This
- ** indicates to the print loop that the end of the document has been reached.
- ** Even if the user indicated in the job dialog to print more pages, setting
- ** gPrintPage to 0 states that the last page has been printed. This is necessary
- ** because the print loop can't know when printing is done. The imaging procedure
- ** is the logical one to state when everything has been imaged. */
-
- #pragma segment TheDoc
- OSErr ImageDocument(FileRecHndl frHndl)
- {
- WindowPtr thePort;
- Rect rct, theInk;
- TEHandle te;
- short pageCol;
- OSErr err;
- static short taskOffset, taskNum;
-
- err = noErr;
- GetPort(&thePort);
-
- if (!gPrintPage) { /* If not printing... */
- DoDrawControls(thePort, false); /* Draw the content controls. */
- }
- else {
-
- if (gPrintPage == 1)
- taskOffset = taskNum = 0;
-
- theInk = thePort->portRect;
- InsetRect(&theInk, 4, 4); /* Just so no characters get clipped. */
-
- pageCol = 0;
- for (rct = theInk; taskNum < 2;) {
- te = (taskNum) ? (*frHndl)->d.doc.outBox : (*frHndl)->d.doc.inBox;
- err = CTEPrint(te, &taskOffset, &rct);
- if (err) break;
- if (taskOffset != -1) return(noErr); /* Text went to bottom of page. */
- taskOffset = 0; /* Done with this TextEdit record. */
- ++taskNum;
- rct.top = rct.bottom + 20;
- rct.bottom = theInk.bottom;
- if (rct.top + 20 >= rct.bottom) return(noErr);
- /* No page left or not enough to bother with. */
- }
- gPrintPage = 0;
- }
-
- return(err);
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* •• You don't call this. DTS.Lib..framework does for appropriate document type(s). •• */
-
- /* This function does the remaining window initialization.
- **
- ** There may be additional content initialization for the window. At this point,
- ** you have a window, but it is currently invisible. If you return noErr, then
- ** the window will be set to the state indicated for that window. Why this function?
- ** You may wish to add controls to the content of the window. You may have a
- ** TextEdit record in the content. All of these sort of things can't be created
- ** until there is a window to contain them. First a document is read in, and then
- ** if the document creation succeeds, a window is created for that document.
- ** At this point we have a document, and we are on our way to having a window.
- ** All that remains is any additional content initialization. Do it, return
- ** noErr, and everybody's happy. If something goes wrong here, return the error,
- ** and the incomplete window will be disposed of. */
-
- #pragma segment TheDoc
- OSErr InitContent(FileRecHndl frHndl, WindowPtr window)
- {
- OSErr err;
- WindowPtr oldPort;
- ControlHandle ctl;
- TEHandle te;
- Handle text;
- StScrpHandle styl;
-
- err = AddControlSet(window, (*frHndl)->fileState.sfType, kwStandardVis, 0, 0, nil);
- if (err) return(err);
-
- GetPort(&oldPort);
- SetPort(window);
-
- CNum2Ctl(window, 100, &ctl);
- (*frHndl)->d.doc.inBox = (TEHandle)GetControlReference(ctl);
-
- CNum2Ctl(window, 101, &ctl);
- (*frHndl)->d.doc.outBox = te = (TEHandle)GetControlReference(ctl);
- CTESetFastKeys(te, GoFast);
-
- text = (*frHndl)->d.doc.textHndl;
- if (text) {
- styl = (*frHndl)->d.doc.textStyl;
- DisposeHandle(CTESwapText(te, text, styl, false));
- (*frHndl)->d.doc.textHndl = nil;
- if (styl) {
- DisposeHandle((Handle)styl);
- (*frHndl)->d.doc.textStyl = nil;
- }
- }
-
- ResizeContent(window, 0, 0);
-
- if (!(*frHndl)->connect.connected) {
- if (!(*frHndl)->connect.remoteLoc.dataHandle) {
- CNum2Ctl(window, 1010, &ctl);
- (*ctl)->contrlVis = 0xFF;
- }
- }
-
- SetDocSize(frHndl, kwNoChange, 4096);
-
- SetPort(oldPort);
- return(noErr);
- }
-
- static Boolean GoFast(TEHandle teHndl, EventRecord *event)
- {
- #ifndef __MWERKS__
- #pragma unused (teHndl)
- #endif
-
- if (event->modifiers & cmdKey) return(false);
- return(true);
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* •• You don't call this. DTS.Lib..framework does for appropriate document type(s). •• */
-
- #pragma segment TheDoc
- OSErr ReadDocument(FileRecHndl frHndl)
- {
- short fileRefNum, oldRes;
- OSErr err;
- char hstate;
- long count;
- Handle textHndl;
- StScrpHandle styl;
- ConnectRec **ach;
- AEAddressDesc remoteLoc;
- long timeout;
-
- fileRefNum = (*frHndl)->fileState.refNum;
-
- err = SetFPos(fileRefNum, fsFromStart, 0);
- /* Set the file position to the beginning of the file. */
-
- if (!err)
- err = DoReadDocumentHeader(frHndl);
- /* Read the document header.
- ** Note that this doesn't guarantee that we will actually do something.
- ** Text documents don't have a header. The read and write header procs have
- ** been set to nil for text documents, so calling DoReadDocumentHeader
- ** will do nothing for text documents. DTS.StyleChat documents do have a header,
- ** and by calling DoReadDocumentHeader, the header will be read in. */
-
- if (err == resNotFound) err = noErr;
-
- if (!err) { /* Read TextEdit text from file. */
- textHndl = NewHandle(kMaxNumChars);
- if (!(err = MemError())) {
- count = kMaxNumChars;
- /* The size of the text isn't saved to disk. This is the maximum
- ** that a TextEdit record can accept. */
- hstate = LockHandleHigh(textHndl);
- err = FSRead(fileRefNum, &count, *textHndl);
- HSetState(textHndl, hstate);
-
- if (err == eofErr)
- err = noErr;
-
- if (err)
- count = 0;
-
- SetHandleSize(textHndl, count);
- /* Set the handle to the actual size of the text on disk. */
- (*frHndl)->d.doc.textHndl = textHndl;
- }
- }
-
- if (!err) {
- err = UseDocResFile(frHndl, &oldRes, fsRdWrPerm);
- if (!err) {
- styl = (StScrpHandle)GetResource(kStylResType, kStylResID);
- if (styl)
- DetachResource((Handle)styl);
- (*frHndl)->d.doc.textStyl = styl;
- }
- UseResFile(oldRes);
- }
-
- if (!err) {
- err = UseDocResFile(frHndl, &oldRes, fsRdWrPerm);
- if (!err) {
- ach = (ConnectRec **)GetResource(kAutoConnectResType, kAutoConnectResID);
- if (ach) {
- BlockMove(*ach, &(*frHndl)->connect, sizeof(ConnectRec));
- (*frHndl)->connect.connected = false;
- (*frHndl)->connect.remoteLoc.dataHandle = nil;
- DetachResource((Handle)ach);
- DisposeHandle((Handle)ach);
- if ((*frHndl)->connect.remoteMachine[0]) {
- LaunchRemoteApp(frHndl);
- for (timeout = TickCount() + 600; timeout > TickCount();) {
- err = GetRemoteProcessTarget(frHndl, &remoteLoc, AEPortFilter);
- if (err) break;
- if (remoteLoc.dataHandle) {
- (*frHndl)->connect.remoteLoc = remoteLoc;
- SendConnect(frHndl, (char *)"\pDTS.Chat");
- break;
- }
- }
- }
- }
- }
- UseResFile(oldRes);
- }
-
- return(err);
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* •• You don't call this. DTS.Lib..framework does for appropriate document type(s). •• */
-
- /* Resize application specific content (Called by ResizeWindow).
- **
- ** This gets called when a user does a zoom or window resizing operation.
- ** It is possible that things in the content need to be resized in conjunction
- ** with the resizing of the window. */
-
- #pragma segment TheDoc
- void ResizeContent(WindowPtr window, short oldh, short oldv)
- {
- #ifndef __MWERKS__
- #pragma unused (oldh, oldv)
- #endif
-
- FileRecHndl frHndl;
- WindowPtr oldPort;
- short i;
- Rect crct, rct;
- TEHandle te;
-
- if (!window) return;
-
- frHndl = (FileRecHndl)GetWRefCon(window);
- oldPort = SetFilePort(frHndl);
-
- GetContentRect(window, &crct);
- OffsetRect(&crct, -crct.left, -crct.top);
- for (i = 0; i < 2; ++i) {
- rct = crct;
- --rct.top;
- --rct.left;
- rct.right -= 14;
-
- rct.bottom = rct.top + (rct.bottom - rct.top + 1) / 2;
- if (i) {
- rct.top = rct.bottom - 1;
- rct.bottom = crct.bottom + 1;
- }
-
- te = (i) ? (*frHndl)->d.doc.outBox : (*frHndl)->d.doc.inBox;
- CTEMove(te, rct.left, rct.top);
- CTESize(te, rct.right - rct.left, rct.bottom - rct.top, true);
- }
-
- SetPort(oldPort);
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* •• You don't call this. DTS.Lib..framework does for appropriate document type(s). •• */
-
- /* Scroll application specific frame (Called by DoScrollFrame).
- **
- ** Some applications may need to scroll the "frame" of the document along
- ** with the document contents. This is common for applications with rulers,
- ** or other similar sidebar items. */
-
- #pragma segment TheDoc
- void ScrollFrame(FileRecHndl frHndl, WindowPtr window, long dh, long dv)
- {
- #ifndef __MWERKS__
- #pragma unused (frHndl, window, dh, dv)
- #endif
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* •• You don't call this. DTS.Lib..framework does for appropriate document type(s). •• */
-
- /* Since the hierarchical document package isn't used by DTS.StyleChat,
- ** this function actually never gets called. */
-
- #pragma segment TheDoc
- void UndoFixup(FileRecHndl frHndl, Point contOrg, Boolean afterUndo)
- {
- #ifndef __MWERKS__
- #pragma unused (frHndl, contOrg, afterUndo)
- #endif
-
- /* See DTS.Draw for an example of what you might do here. */
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* •• You don't call this. DTS.Lib..framework does for appropriate document type(s). •• */
-
- /* This function is where you adjust the cursor to reflect the location in the
- ** document or window. You have the additional input of gCursorRgn to deal
- ** with. The way that the cursor handling works is as follows:
- ** 1) The application calls DoWindowCursor().
- ** 2) DoWindowCursor() works its way through the windows/documents, front to back.
- ** It looks at the document's windowCursorProc and checks to see if the document
- ** has one. If the document doesn't have one, then it assumes that that window
- ** always wants an arrow. If the cursor is over that window, the cursor is set
- ** to an arrow, and we're done. If the cursor isn't over the window, then the next
- ** window is tried. If all documents don't have a windowCursorProc, then the cursor
- ** is set to an arrow (for the non-document area of the screen).
- ** 3) If a document has a windowCursorProc, then the proc is called. The proc's
- ** job is as follows:
- ** a) If the cursor is over a position that is determined by the window, then
- ** the proc removes other areas from gCursorRgn. Note that it should not
- ** simply set the area to what it "thinks" is the correct area. This window
- ** may not be the front-most. Other windows will have already been subtracted
- ** from gCursorRgn. The resultant gCursorRgn is the correct cursor area,
- ** and should be passed to WaitNextEvent calls in the application (already the case
- ** in EventLoop.c). Also, the cursor should be set to the correct cursor, of course.
- ** You should also return true, as the cursor has been determined.
- ** b) If the cursor is not over a position for this window, then you should
- ** return. You will either pass back true or false. If you don't wish
- ** windows behind this window to have a shot at cursor determination, then
- ** return true. This states that the cursor is "determined". It is, in the
- ** sense that no further determination will occur. If you return false, then
- ** other windows get a shot at determining the cursor.
- **
- ** Setting the cursor to the correct cursor isn't as easy as you would expect.
- ** DTS.Lib..framework uses the global gCursorPtr as the reference to the cursor. This is
- ** fine if the cursor is pointer-based, but if the cursor is resource-based, it is a bit
- ** more of a problem. What you will need to do is to call DoSetResCursor() to make the
- ** resource cursor pointer-based. DoSetResCursor() will set gCursorPtr to nil, and it
- ** also returns the pointer to the permanent copy of the cursor resource. Just set gCursorPtr
- ** to the return result of DoSetResCursor(), and you will be set. */
-
- #pragma segment TheDoc
- Boolean WindowCursor(FileRecHndl frHndl, WindowPtr window, Point globalPt)
- {
- WindowPtr oldPort;
- RgnHandle contRgn;
- Rect outBoxRct, teViewRct, contRct;
- TEHandle outBox, teHndl;
- ControlHandle viewCtl;
- Point contOrg;
-
- /* For the DTS.StyleChat sample, we display an i-beam cursor when over the outbox. */
-
- if (!window) {
- SetCursor(gCursorPtr = &qd.arrow);
- return(true);
- }
-
- oldPort = SetFilePort(frHndl);
- GetContentOrigin((window = (*frHndl)->fileState.window), &contOrg);
- SetOrigin(contOrg.h, contOrg.v); /* Scroll position of window. */
-
- viewCtl = CTEViewFromTE(outBox = (*frHndl)->d.doc.outBox);
- outBoxRct = (*viewCtl)->contrlRect; /* Local coordinates of outbox. */
- InsetRect(&outBoxRct, 2, 2);
-
- GetContentRect(window, &contRct);
- /* This returns the content portion of the window in local coordinates,
- ** less document scrollbar and sidebar areas. */
-
- SectRect(&outBoxRct, &contRct, &outBoxRct);
- /* Part of the outbox still visible after scrolling. */
-
- LocalToGlobalRect(&outBoxRct); /* The outbox rect, in global coordinates. */
-
- SetPort(oldPort); /* Put the port back. */
-
- CopyRgn(((WindowPeek)window)->contRgn, (contRgn = NewRgn()));
-
- if (CTETargetInfo(&teHndl, &teViewRct) == window) {
- /* If target TextEdit control belongs to this window... */
-
- if ((teHndl == outBox) && (PtInRect(globalPt, &outBoxRct))) {
- /* If target TextEdit control is the outbox, and the cursor
- ** is over the visible part of the outbox... */
-
- gCursorPtr = DoSetResCursor(ibeamCursor);
- RectRgn(contRgn, &outBoxRct);
- SectRgn(gCursorRgn, contRgn, gCursorRgn);
- DisposeRgn(contRgn);
- return(true);
- }
- }
-
- return(false);
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* •• You don't call this. DTS.Lib..framework does for appropriate document type(s). •• */
-
- /* After the DTS.Lib framework disposes of a window, it calls here. This is
- ** to give the application a chance to do any additional tasks related to
- ** a window closing. DTS.StyleChat doesn't have anything else extra to do. */
-
- #pragma segment TheDoc
- void WindowGoneFixup(WindowPtr window)
- {
- #ifndef __MWERKS__
- #pragma unused (window)
- #endif
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* •• You don't call this. DTS.Lib..framework does for appropriate document type(s). •• */
-
- /* The reverse function of ReadDocument. */
-
- #pragma segment TheDoc
- OSErr WriteDocument(FileRecHndl frHndl)
- {
- short fileRefNum, oldRes;
- OSErr err;
- char hstate;
- long count, fpos;
- TEHandle te;
- Handle textHndl, oldr, ach;
- StScrpHandle styl;
- ConnectRec ac;
-
- fileRefNum = (*frHndl)->fileState.refNum;
-
- err = SetFPos(fileRefNum, fsFromStart, 0);
- /* Set the file position to the beginning of the file. */
-
- if (!err)
- err = DoWriteDocumentHeader(frHndl);
- /* Write the document header.
- ** Note that this doesn't guarantee that we will actually do something.
- ** Text documents don't have a header. The read and write header procs have
- ** been set to nil for text documents, so calling DoWriteDocumentHeader
- ** will do nothing for text documents. DTS.StyleChat documents do have a header,
- ** and by calling DoWriteDocumentHeader, the header will be written out. */
-
- if (!err) { /* Write out-box TextEdit control text to file. */
- te = (*frHndl)->d.doc.outBox;
- textHndl = (*te)->hText;
- count = (*te)->teLength;
- hstate = LockHandleHigh(textHndl);
- err = FSWrite(fileRefNum, &count, *textHndl);
- HSetState(textHndl, hstate);
- }
-
- if (!err) {
- err = GetFPos(fileRefNum, &fpos);
- if (!err)
- err = SetEOF(fileRefNum, fpos);
- } /* The document may be shorter than last time it was written to disk.
- ** Handle this case by ending the file based on the new length. */
-
- if (!err) {
- styl = CTEGetFullStylScrap((*frHndl)->d.doc.outBox);
- if (styl) {
- err = UseDocResFile(frHndl, &oldRes, fsRdWrPerm);
- if (!err) {
- oldr = GetResource(kStylResType, kStylResID);
- if (oldr) RemoveResource(oldr);
- AddResource((Handle)styl, kStylResType, kStylResID, nil);
- WriteResource((Handle)styl);
- DetachResource((Handle)styl);
- DisposeHandle((Handle)styl);
- }
- UseResFile(oldRes);
- }
- }
-
- if (!err) {
- err = UseDocResFile(frHndl, &oldRes, fsRdWrPerm);
- if (!err) {
- oldr = GetResource(kAutoConnectResType, kAutoConnectResID);
- if (oldr) RemoveResource(oldr);
- ac = (*frHndl)->connect;
- if (ac.remotePath[0]) {
- ach = NewHandle(sizeof(ConnectRec));
- if (ach) {
- BlockMove(&ac, *ach, sizeof(ConnectRec));
- AddResource(ach, kAutoConnectResType, kAutoConnectResID, nil);
- WriteResource(ach);
- DetachResource(ach);
- DisposeHandle(ach);
- }
- }
- }
- UseResFile(oldRes);
- }
-
- return(err);
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* •• You don't call this. DTS.Lib..framework does at open-application time. •• */
-
- #pragma segment TheDoc
- OSErr DoOpenApplication(void)
- {
- MenuHandle menu;
-
- gStartingUp = true;
-
- menu = GetMenuHandle(mFonts);
- if (menu)
- AppendResMenu(menu, 'FONT');
-
- return(noErr);
- }
-
-
-
- /*****************************************************************************/
- /*****************************************************************************/
- /*****************************************************************************/
-
-
-
- /* •• You don't call this. DTS.Lib..framework does for appropriate document type(s). •• */
-
- #pragma segment TheDoc
- Boolean AdjustMenuItems(WindowPtr window, short menuID)
- {
- Boolean redrawMenuBar;
- MenuHandle menu;
-
- redrawMenuBar = false;
-
- switch (menuID) {
- case mFile:
- redrawMenuBar = DoAdjustFileMenu(window);
- break;
- case mEdit:
- redrawMenuBar = DoAdjustEditMenu(window);
- break;
- case mFonts:
- redrawMenuBar = DoAdjustFontsMenu(window);
- break;
- default:
- menu = GetMenuHandle(menuID);
- if (menu)
- (*menu)->enableFlags |= 0xFFFFFFFEL;
- break;
- }
-
- return(redrawMenuBar);
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* •• You don't call this. DTS.Lib..framework does for appropriate document type(s). •• */
-
- #pragma segment TheDoc
- Boolean DoMenuItem(WindowPtr window, short menuID, short menuItem)
- {
- #ifndef __MWERKS__
- #pragma unused (window)
- #endif
-
- return(DoMenuCommand(menuID, menuItem));
- }
-
-
-
- /*****************************************************************************/
- /*****************************************************************************/
- /*****************************************************************************/
-
-
-
- #pragma segment TheDoc
- OSErr DuplicateDocument(FileRecHndl oldFrHndl, FileRecHndl *newFrHndl)
- {
- OSErr err;
- TEHandle te;
- Handle oldHndl, newHndl;
- long size;
-
- err = NewDocument(newFrHndl, (*oldFrHndl)->fileState.sfType, true);
- /* Create a document and root object to copy the file data into. */
-
- if (err) return(err);
-
- te = (*oldFrHndl)->d.doc.outBox;
- oldHndl = (*te)->hText;
- size = (*te)->teLength;
- newHndl = NewHandle(size);
- if (newHndl) {
- (**newFrHndl)->d.doc.textHndl = newHndl;
- BlockMove(*oldHndl, *newHndl, size);
- }
- else {
- err = MemError();
- DisposeDocument(*newFrHndl);
- *newFrHndl = nil;
- }
-
- return(err);
- }
-
-
-
-